﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//using SqlOrm.Xml;

namespace SqlImEx.Sql
{
    public class DataTypeConversion
    {
        public static string GetCLRDataType(Type type)
        {
            Type useType = type;
            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
                useType = type.GetGenericArguments()[0];
            string result = useType.Name;
            if (useType == typeof(string))
                result = "string";
            if (useType == typeof(bool))
                result = "bool";
            if (useType == typeof(int))
                result = "int";
            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
                return result + "?";
            return result;
        }
        public static string GetCLRDataType(Field field)
        {
            string result = field.datatype + "ERROR";
            switch (field.datatype)
            {
                case FieldDataType.bit:
                    {
                        if (field.nulls)
                            result = "bool?";
                        else result = "bool";
                        break;
                    }
                case FieldDataType.datetime:
                    {
                        if (field.nulls)
                            result = "DateTime?";
                        else result = "DateTime";
                        break;
                    }
                case FieldDataType.guid:
                    {
                        if (field.nulls)
                            result = "Guid?";
                        else result = "Guid";
                        break;
                    }
                case FieldDataType.int16:
                    {
                        if (field.nulls)
                            result = "Int16?";
                        else result = "Int16";
                        break;
                    }
                case FieldDataType.int32:
                    {
                        if (field.nulls)
                            result = "int?";
                        else result = "int";
                        break;
                    }
                case FieldDataType.int64:
                    {
                        if (field.nulls)
                            result = "long?";
                        else result = "long";
                        break;
                    }
                case FieldDataType.single:
                    {
                        if (field.nulls)
                            result = "Single?";
                        else result = "Single";
                        break;
                    }
                case FieldDataType.@float:
                    {
                        if (field.nulls)
                            result = "double?";
                        else result = "double";
                        break;
                    }
                case FieldDataType.@decimal:
                    {
                        if (field.nulls)
                            result = "decimal?";
                        else result = "decimal";
                        break;
                    }
                case FieldDataType.@byte:
                    {
                        if (field.nulls)
                            result = "byte?";
                        else result = "byte";
                        break;
                    }
                case FieldDataType.bytearray:
                    {
                        result = "byte[]";
                        break;
                    }
                case FieldDataType.@string:
                    result = "string";
                    break;
                case FieldDataType.@object:
                    result = "object";
                    break;
            }
            //if (!string.IsNullOrEmpty(field.EnumName))
            //{
            //    field.UnderlyingEnumType = result.Replace("?", "");
            //    if (field.nulls)
            //        result = field.EnumName + "?";
            //    else result = field.EnumName;
            //}
            if (result.EndsWith("ERROR"))
                throw new Exception("Unkown Type");
            return result;
        }

        public static FieldDataType GetType(string sqltype)
        {
            switch (sqltype)
            {
                case "real":
                    return FieldDataType.single;
                case "image":
                    return FieldDataType.bytearray;
                case "char":
                    return FieldDataType.@string;
                case "varchar":
                    return FieldDataType.@string;
                case "ntext":
                    return FieldDataType.@string;
                case "nvarchar":
                    return FieldDataType.@string;
                case "sysname":
                    return FieldDataType.@string;
                case "nchar":
                    return FieldDataType.@string;
                case "text":
                    return FieldDataType.@string;
                case "bit":
                    return FieldDataType.bit;
                case "int":
                    return FieldDataType.int32;
                case "tinyint":
                    return FieldDataType.@byte;
                case "bigint":
                    return FieldDataType.int64;
                case "smallint":
                    return FieldDataType.int16;
                case "float":
                    return FieldDataType.@float;
                case "decimal":
                    return FieldDataType.@decimal;
                case "datetime":
                    return FieldDataType.datetime;
                case "datetime2":
                    return FieldDataType.datetime;
                case "date":
                    return FieldDataType.date;
                case "uniqueidentifier":
                    return FieldDataType.guid;
                case "sql_variant":
                    return FieldDataType.@object;
                case "varbinary":
                    return FieldDataType.bytearray;
                case "timestamp":
                    return FieldDataType.timestamp;
                case "numeric":
                    return FieldDataType.@decimal;
                case "money" :
                    return FieldDataType.@decimal;
                case "xml":
                    return FieldDataType.@string;
                case "time" :
                    return FieldDataType.timespan;
            }
            throw new Exception("Unkown Type " + sqltype);
        }

        public static Type GetType(Field field)
        {
            //string result = field.datatype + "ERROR";
            Type result = typeof(void);
            switch (field.datatype)
            {
                case FieldDataType.bit:
                    result = typeof(bool);
                    break;
                case FieldDataType.datetime:
                    {
                        if (field.nulls)
                            result = typeof(DateTime?);
                        else result = typeof(DateTime);
                        break;
                    }
                case FieldDataType.guid:
                    {
                        if (field.nulls)
                            result = typeof(Guid?);
                        else result = typeof(Guid);
                        break;
                    }
                case FieldDataType.int16:
                    {
                        if (field.nulls)
                            result = typeof(Int16?);
                        else result = typeof(Int16);
                        break;
                    }
                case FieldDataType.int32:
                    {
                        if (field.nulls)
                            result = typeof(int?);
                        else result = typeof(int);
                        break;
                    }
                case FieldDataType.int64:
                    {
                        if (field.nulls)
                            result = typeof(long?);
                        else result = typeof(long);
                        break;
                    }
                case FieldDataType.@float:
                    {
                        if (field.nulls)
                            result = typeof(double?);
                        else result = typeof(double);
                        break;
                    }
                case FieldDataType.@decimal:
                    {
                        if (field.nulls)
                            result = typeof(decimal?);
                        else result = typeof(decimal);
                        break;
                    }
                case FieldDataType.@byte:
                    {
                        if (field.nulls)
                            result = typeof(byte?);
                        else result = typeof(byte);
                        break;
                    }
                case FieldDataType.bytearray:
                    {
                        result = typeof(byte[]);
                        break;
                    }
                case FieldDataType.@string:
                    {
                        result = typeof(string);
                        break;
                    }
            }
            if (result == typeof(void))
                throw new Exception("Uknown Type");
            return result;
        }

        //public static string GetUnderlyingEnumDataType(Field field)
        //{
        //    if (!string.IsNullOrEmpty(field.EnumName))
        //    {
        //        if (field.nulls)
        //            return field.EnumName + "?";
        //        return field.EnumName;
        //    }
        //    return "ERROR";
        //}

        public static string GetSQL(Field field)
        {
            string result = field.datatype + "ERROR";
            switch (field.datatype)
            {
                case FieldDataType.bit:
                    result = "bit";
                    break;
                case FieldDataType.datetime:
                    result = "datetime";
                    break;
                case FieldDataType.guid:
                    result = "uniqueidentifier";
                    break;
                case FieldDataType.int16:
                    result = "smallint";
                    break;
                case FieldDataType.int32:
                    result = "integer";
                    break;
                case FieldDataType.int64:
                    result = "bigint";
                    break;
                case FieldDataType.@float:
                    result = "double";
                    break;
                case FieldDataType.@decimal:
                    result = "decimal";
                    break;
                case FieldDataType.@string:
                    {
                        string len = (field.len > 0) ? field.len.ToString() : "MAX";
                        result = string.Format("varchar({0})", len);
                        break;
                    }
            }
            //if (!string.IsNullOrEmpty(field.EnumName))
            //{
            //    //if (field.nulls)
            //    //    result = StaticFields.SqlDataTypeEnum + "?";
            //    //else 
            //    result = StaticFields.SqlDataTypeEnum;
            //}
            return result;
        }

        public static string GetSqlDbType(Field field)
        {
            switch (field.datatype)
            {
                case FieldDataType.bit:
                    return "SqlDbType.Bit";
                case FieldDataType.single:
                    return "SqlDbType.Real";
                case FieldDataType.bytearray:
                    return "SqlDbType.Binary";
                case FieldDataType.datetime:
                    return "SqlDbType.DateTime";
                case FieldDataType.guid:
                    return "SqlDbType.UniqueIdentifier";
                case FieldDataType.int16:
                    return "SqlDbType.SmallInt";
                case FieldDataType.int32:
                    return "SqlDbType.Int";
                case FieldDataType.int64:
                    return "SqlDbType.BigInt";
                case FieldDataType.@float:
                    return "SqlDbType.Float";
                case FieldDataType.@decimal:
                    return "SqlDbType.Decimal";
                case FieldDataType.@byte:
                    return "SqlDbType.TinyInt";
                case FieldDataType.@object:
                    return "SqlDbType.Object";
                case FieldDataType.@string:
                    {
                        return "SqlDbType.VarChar";
                    }
            }
            throw new Exception("Uknown DataType");
        }

        public static bool IsNullableType(Field field)
        {
            switch (field.datatype)
            {
                case FieldDataType.bit:
                    return true;
                case FieldDataType.datetime:
                    return true;
                case FieldDataType.guid:
                    return true;
                case FieldDataType.int16:
                    return true;
                case FieldDataType.int32:
                    return true;
                case FieldDataType.int64:
                    return true;
                case FieldDataType.@float:
                    return true;
                case FieldDataType.@decimal:
                    return true;
            }
            return false;
        }
        public static string CsharpTSql(Field field)
        {
            if (field.datatype == FieldDataType.datetime || field.datatype == FieldDataType.guid || field.datatype == FieldDataType.@string)
                return "'\" + " + field.name + " + \"'";
            return "\" + " + field.name + "  + \"";
        }
        public static string ValueToSqlValue(Field field, string value)
        {
            value = value.Replace("'", "''");
            if (field.datatype == FieldDataType.date ||
                field.datatype == FieldDataType.datetime || 
                field.datatype == FieldDataType.@string || 
                field.datatype == FieldDataType.guid )
                return "'" + value + "'";
            else if (field.datatype == FieldDataType.bytearray)
            {
                byte[] bytearr = Convert.FromBase64String(value);
                return "0x" + BitConverter.ToString(bytearr).Replace("-", "");
            }
            else if (field.datatype == FieldDataType.timestamp)
            {
                return "current_timestamp";
            }
            else
                return value;
        }
    }
}
